C++开发环境构建

Catalogue
  1. 1.编译器
    1. 1.1 编译和运行
  2. 2. c++版本/clang版本
  3. 3.库和库管理
    1. 3.1 库
      1. 3.1.1 C++标准库
      2. 3.1.2 STL和Boost
    2. 3.2 库管理
      1. 3.2.1 环境变量
      2. 3.2.2 CommandLineTools和XCode
      3. 3.2.3 llvm和clang
      4. 3.2.4 GCC和GDB
  4. 4.构建
    1. 4.1 make
      1. 4.1.1 Makefile
    2. 4.2 cmake
      1. 4.2.1 什么是cmake
      2. 4.2.2 cmake使用方法
      3. 4.2.3 高级用法
      4. 4.2.1 版本查看
  5. 5.常见库及问题
    1. 5.1 xgboost项目构建和调试
      1. (1.)unsupported option ‘-fopenmp’
  6. 6. C++环境验证
    1. 6.1 当前环境下使用的 c++的标准库路径?
    2. 6.2 vscode环境

C++的开发环境,目前常用的IDE是vscode。 macOS安装 开发工具(例如xcode、commondlinetools) 之后,其包含了c++的标准库。
通过环境变量等方法正确的引入标准库以及三方库 即可实现 基于vscode开发 c++的项目。

然而,环境搭建的过程中,重要的是:

  • 对于编译器、构建工具、库及其管理 的理解、对C++版本的理解。
  • 如何使用 vscode、clang++、make、cmake 开发和构建 c++的项目;如何debug调试;以及理解这些工具和过程的原理。
  • 可能会遇到哪些常见的问题? 怎么解决、以及怎么持续深入学习c++的项目。

1.编译器

常见的编译器有:GCC、Clang、Microsoft Visual C++等等。
clang更加现代化、模块化,编译速度更快,适合大型项目

许多编译器即支持c也支持c++,但对于c++的一些新特性和复杂的语法结构,编译器的优化和处理可能有所不同。

1.1 编译和运行

最简单的C程序

1
2
3
4
5
6
# include<stdio.h>
int main()
{
printf("This is a C program.\n");
return 0;
}

编译与运行

1
2
3
4
5
gcc helloworld.c -o helloworld
# 或者 clang example.c -o example
./helloworld
# 输出结果
This is a C program.

2. c++版本/clang版本

不同来源版本的clang可能存在差异
mac系统自带的Clang编译器不支持OpenMP,需要手动安装Clang(基于llvm),即 brew install llvm.
然后配置环境变量,后续所有开发场景都可以使用此版本的clang和基于llvm的工具。

clang++版本

这些编译工具(clang/g++) 路径在xcode或者commondlinetools 路径下.

1.怎么理解c++的版本?

2.clang的版本和c++版本的关系?

3.clang版本的区别?和make有兼容性问题吗?

4.怎么查看c++的库路径和版本信息?
mac系统库路径一般在:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib

1
2
3
libc++.1.tbd
libc++.tbd
libc++abi.tbd

.tbd 是苹果操作系统的文件格式,用于描述动态库的符号信息。以上3个是C++标准库的实现
linux中呢?

3.库和库管理

c++相关的库 一般在开发工具的环境路径/目录(/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib)、
以及 系统的基础lib路径(/usr/lib、/usr/local/lib/)下。 例如mac中,在xcode、Command Line Tools 工具的路径下。
开发环境、运行时环境项目 会从这些路径下找 需要的库内容。 「c++主要涉及 头文件(include)、库文件(lib)路径」

3.1 库

c++的库.

3.1.1 C++标准库

提供了一些列重要的模块。
(容器、算法、迭代器、字符串、输入输出、智能指针、线程、日期和时间、类型特性、元编程、异常处理等)

3.1.2 STL和Boost

STL 和 Boost 是 C++ 开发中两个重要的库。
STL(标准模板库)是 C++ 标准库的一部分
Boost 是一个大型的开源 C++ 库集合,它提供了许多扩展功能和库,这些库在功能和性能上都经过了严格的测试和验证。Boost 的设计目的是为 C++ 开发者提供可重用的组件,许多 Boost 库的设计理念和接口最终被采纳到 C++ 标准库中。

STL 是 C++ 开发的基础库,而 Boost 则是 C++ 开发的高级库,提供了更多扩展和增强功能。两者在 C++ 编程中各有其重要作用,Boost 库中的许多功能也为 C++ 标准库的演进做出了贡献。

3.2 库管理

介绍下 通过环境变量 正确、方便的 引入开发环境/项目。
另外介绍下 常见的安装的软件的 开发相关的库。

项目是如果找到 这些库的呢?
以c++库和头文件为例:

  1. 当前目录、当前项目
  2. 编译时指定的头文件目录(有 -I -L 参数指定)
  3. 系统环境变量 CPLUS_INCLUDE_PATH 或 C_INCLUDE_PATH 指定的目录
  4. gcc默认目录: /usr/include;/usr/local/include;等等.(各系统平台可能会有不同)

3.2.1 环境变量

和java同理,要用这些 不同路径下的 库和头文件,可能会涉及 环境变量的配置。 或者ide环境的配置。
主要目的是通过环境变量 正确、方便的 将需要的库引入开发环境/项目。
(有些ide中直接配置即可,不用配置环境变量;但通过环境变量配置可能后续使用起来更方便些)

常见的库路径如下:

来源 说明 路径
CommandLineTools CommandLineTools /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
XCode XCode /Applications/Xcode.app/Contents/Developer/Platforms/ MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib
系统库 通常是系统自带的库文件(属于系统核心部分) /usr/lib/
系统(手动安装) 类Unix系统(如macOS/Linux)中常用的目录,存放本地安装的库文件(手动或第三方软件安装) /usr/local/lib/
本地头文件 类Unix系统(如macOS/Linux)中常用的目录,存放本地安装的库文件(手动或第三方软件安装) /usr/local/include/

当手动安装或者下载的第三方的软件的路在别的指定路径下,需要在某个项目中使用时。 相关的库和头文件 路径可以通过 环境变量的配置引入项目。 例如:

1
2
3
export CPATH=$CPATH:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include

3.2.2 CommandLineTools和XCode

这两个都是mac上的开发工具。 CommandLineTools 是轻量级的,主要提供了命令行开发工具; XCode是功能强大的集成开发环境(IDE).
如果是iOS、macOS、watchOS和tvOS的开发,可以安装XCode; 其它情况,建议安装CommandLineTools即可(仅几百M)

类型 CommandLineTools XCode
安装包大小 几百M 几个GB,甚至10多GB
用途 主要提供命令行工具,如编译器(Clang、GCC等)、链接器、调试器(LLDB)和其他基本的开发工具 功能强大的集成开发环境(IDE),代码编辑、调试、界面设计、版本控制等;模拟器、性能分析、测试等高级功能
使用场景 常用于 脚本编写、小型项目开发、自动化构建等 适合专业的IOS和macOS应用程序开发,以及需要图形界面设计和高级开发功能的项目
更新方式 通过命令行工具(如xcode-select —install) 通过Mac App Store进行更新,需要较长时间

一些c++的项目,需要的 三方库和头文件,可以通过引入 CommandLineTools 下的

3.2.3 llvm和clang

1.什么是LLVM?
LLVM(Low Level Virtual Machine) 是一个开源的 编译器基础设施项目。

2.包含的工具集?

  • 包括Clang编译器,它是一个基于LLVM的C、C++和Objective-C 编译器。
  • LLDB调试器,用于调试程序。
  • 其他工具如lli(LLVM解释器)、llvm-link(链接器)等

3.有什么特点和优势?

  • 可扩展性、性能优化、跨平台、开源和活跃的社区。

4.能做什么?

  • 编译器开发
  • 代码优化
  • 程序分析和调试
  • 跨平台开发
  • 工具和库(Clang、LLDB、Polly)

安装和查看

1
2
3
4
5
6
7
8
9
10
11
# mac默认的一般是 基于xcode中的。 建议自己安装
brew install llvm

# 查看
brew info llvm

# 配置环境变量
export PATH="/usr/local/opt/llvm/bin:$PATH"
## 这样 clang也是基于llvm的。 而不是基于xcode的clang 15.0.0版本
## 实质的 安装路径在:/usr/local/Cellar/llvm/ /usr/local/opt/llvm/ 是链接过去的
## 不同版本的macOS系统,homebrew 安装这种三方工具的 路径不太一样(新版系统 在/opt/homebrew/...)

3.2.4 GCC和GDB

重点:谈到 llvm和clang, 同样的介绍下 GCC和GDB。

  1. clang是LLVM项目的一部分, 是一个开源的编译器前端。
  2. 而gcc 是GUN Compiler Collection的缩写,是一个成熟的开源编译器集合
  3. 使用 Clang 还是 GCC?如果 Clang 能够完全满足你的编译需求, 并且不依赖GCC特有的功能,那么可以仅使用clang。
    如果老项目基于GCC,可能需要同时使用gcc和clang。

GDB 类似 lldb 主要用于调试(生成调试信息)。

两者的比较:
LLVM 和 Clang 在设计上较为现代,提供了优秀的错误和警告信息、更快的编译速度、更好的 C++ 标准支持和先进的静态分析工具。
GCC 依然是一个成熟、稳定且功能强大的编译器,具有广泛的语言和平台支持,适合很多传统和生产环境。

4.构建

构建工具 类似java的 maven,用于较大型项目的构建。常见的构建工具包括:make、cmake、bazel。

  • make是传统的构建工具,简单高效,适合小到中型项目、在Unix和类Unix系统上使用。
  • cmake是跨平台(win/linux/macOS/android等)的构建工具,广泛用于C和C++项目。 通过「CMakeLists.txt」描述项目构建过程。

4.1 make

make是个构建工具,类似于maven。
Makefile定义了项目的依赖关系和构建规则。

1.发展背景和现状
make起源于AT&T贝尔实验室,当前由FSF维护, GUN项目提供make的GUN版本。(目前大多数开发环境和操作系统中使用的make实际上是指GUN make,简称make)

2.make的基本概念
Makefile、目标、依赖、规则。

4.1.1 Makefile

Makefile的基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 变量定义 「定义了 (CC) 和编译选项 (CFLAGS)」
CC = gcc
CFLAGS = -Wall -g

# 目标规则
myprogram: main.o foo.o
$(CC) -o myprogram main.o foo.o
## myprogram 是最终生成的可执行文件,它依赖于 main.o 和 foo.o。
## 生成 myprogram 的命令是 $(CC) -o myprogram main.o foo.o。

main.o: main.c
$(CC) $(CFLAGS) -c main.c
## main.o 是一个目标文件,它依赖于 main.c 源文件。生成 main.o 的命令是 $(CC) $(CFLAGS) -c main.c。

foo.o: foo.c
$(CC) $(CFLAGS) -c foo.c

# 清理规则
clean:
rm -f myprogram main.o foo.o

xgboost的Makefile解读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 变量定义 「定义了 (CC) 和编译选项 (CFLAGS)」
CC = gcc
CFLAGS = -Wall -g

# 目标规则
myprogram: main.o foo.o
$(CC) -o myprogram main.o foo.o
## myprogram 是最终生成的可执行文件,它依赖于 main.o 和 foo.o。
## 生成 myprogram 的命令是 $(CC) -o myprogram main.o foo.o。


ALL_DEP = $(filter-out build/cli_main.o, $(ALL_OBJ)) $(LIB_DEP)
# 这个函数调用从 $(ALL_OBJ) 中排除 build/cli_main.o 文件,返回剩余的对象文件列表。

CLI_OBJ = build/cli_main.o

build/%.o: src/%.cc
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -MM -MT build/$*.o $< >build/$*.d
$(CXX) -c $(CFLAGS) $< -o $@

xgboost: $(CLI_OBJ) $(ALL_DEP)
$(CXX) $(CFLAGS) -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
## 目标:xgboost 是我们要构建的目标,通常是一个可执行文件。
## 依赖:$(CLI_OBJ) 和 $(ALL_DEP) 是构建 xgboost 所需的依赖文件或对象。
## $(CLI_OBJ) 可能是编译生成的对象文件,而 $(ALL_DEP) 可能包括其他需要的文件(如库文件或额外的对象文件)。

## $(CXX):这是编译器变量,通常设置为 C++ 编译器,如 g++ 或 clang++。
## $(CFLAGS):这些是编译标志,通常用于设置编译器选项,如优化级别和调试信息。对于链接阶段,这个变量可能会被用来设置链接选项。
## -o $@:$@ 是自动变量,表示规则中的目标,即 xgboost。-o 选项用于指定输出文件名。
## $(filter %.o %.a, $^):$^ 是自动变量,表示所有依赖文件的列表。$(filter %.o %.a, $^) 是一个函数,用于筛选出扩展名为 .o 和 .a 的文件。
## 这个函数确保只有 .o 对象文件和 .a 库文件被传递给链接器。
## $(LDFLAGS):这些是链接标志,用于设置链接器选项,例如库路径和库文件。


main.o: main.c
$(CC) $(CFLAGS) -c main.c
## main.o 是一个目标文件,它依赖于 main.c 源文件。生成 main.o 的命令是 $(CC) $(CFLAGS) -c main.c。


foo.o: foo.c
$(CC) $(CFLAGS) -c foo.c


# 清理规则
clean:
rm -f myprogram main.o foo.o

构建过程中,是怎么找到依赖的。 比如 每个源文件是单独构建的,构建的时候,如果依赖其它的 构建,这个关系怎么找到的?
也就是说 怎么知道那个需要先构建?

4.2 cmake

CMake是一个 构建系统生成器。 主要作用是 生成特定与平台和构建工具的构建配置文件。
实际的构建过程则依赖生成的这些构建配置文件所对应的构建工具。

4.2.1 什么是cmake

cmake相比较make,有以下优点:

  • 跨平台支持:支持多种操作系统,如Linux、macOS、Windows等。能够生成适用于不同平台的构建系统配置文件。
  • 构建配置:通过一个或多个CMakeLists.txt文件来描述项目的配置。
  • 自动化和简化构建:生成适用于不同构建工具的配置文件, 使得用户可以使用选择喜欢的构建工具(make/MSBuild等)
    如果系统中有多个C编译器,可以明确指定要使用的编译器

4.2.2 cmake使用方法

CMakeLists.txt

1. 安装cmake

1
2
3
4
5
6
7
# macOS
brew install cmake
# linux
sudo apt-get install cmake # 对于 Debian/Ubuntu 系统
sudo yum install cmake # 对于 Red Hat/CentOS 系统
# Window
choco install cmake

2. 创建CMakeLists.txt
CMakeLists.txt 文件是 CMake 的核心配置文件,用于描述构建项目的规则。一个基本的 CMakeLists.txt 文件可能如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cmake_minimum_required(VERSION 3.10)  # 设置 CMake 的最低版本要求
project(MyProject VERSION 1.0) # 定义项目名称和版本

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 添加可执行文件
add_executable(MyExecutable main.cpp foo.cpp)

#cmake_minimum_required:指定所需的 CMake 最低版本。
#project:定义项目的名称和版本。
#set:设置 CMake 变量,这里设置 C++ 标准。
#add_executable:定义要生成的可执行文件及其源文件。

3. 创建构建目录

1
2
mkdir build
cd build

4. 生成构建系统配置文件

1
2
# 在构建目录中运行 CMake,指定源代码目录(通常是 .. 表示上级目录):
cmake ..

5. 执行构建
使用make等构建工具执行

4.2.3 高级用法

1.定义库

1
2
add_library(MyLibrary STATIC lib.cpp)
target_link_libraries(MyExecutable PRIVATE MyLibrary)

2.查找和使用外部库

1
2
3
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(MyExecutable ${OpenCV_LIBS})

1
2
3
4
5
6
7
8
9
10
# 设置编译选项:
target_compile_options(MyExecutable PRIVATE -Wall -Wextra)
# 设置构建选项
option(USE_CUSTOM_FEATURE "Enable custom feature" OFF)
if(USE_CUSTOM_FEATURE)
add_definitions(-DCUSTOM_FEATURE)
endif()
# 运行测试
enable_testing()
add_test(NAME MyTest COMMAND MyExecutable)

4.2.1 版本查看

1
2
3
4
5
6
7
8
9
clang --version

# 查看c++版本
g++ --version
# 或者
clang++ --version

# 查看cmake
cmake --version

5.常见库及问题

5.1 xgboost项目构建和调试

xgboost项目构建和调试过程中遇到的问题?
主要就是 mac系统自带的Clang编译器不支持OpenMP,需要手动安装Clang(基于llvm),即 brew install llvm.

(1.)unsupported option ‘-fopenmp’

1.命令

1
2
clang++ -DDMLC_LOG_CUSTOMIZE=1 -std=c++11 -Wall -Wno-unknown-pragmas -Iinclude   -Idmlc-core/include -Irabit/include 
-I/include -O3 -funroll-loops -msse2 -fPIC -fopenmp -MM -MT build/learner.o src/learner.cc >build/learner.d

2.现象
clang: error: unsupported option ‘-fopenmp’
make: * [build/learner.o] Error 1

3.问题分析
OpenMP 是一个用于多处理器编程的应用程序接口(API),专门设计用于在共享内存系统上并行化计算密集型任务。
是一种编写并行程序的标准化工具,可以显著简化多线程编程的复杂性。
OpenMP的执行模式采用fork-join模式

出现以上问题,可能的原因有:

  • Clang版本不支持OpenMP
  • 未安装OpenMP运行时库
  • Clang配置问题:你的 Clang 安装可能没有启用 OpenMP 支持。需要确保使用的 Clang 编译器版本正确地配置了 OpenMP。
    (重点):1. 开头使用 c++ 进行编译. 2. 改为clang++后还是提示。 因此可能是clang编译器的原因
1
2
#macOS 自带的 Clang 编译器可能不支持 OpenMP,因此你可以通过 Homebrew 安装一个支持 OpenMP 的 Clang 版本
brew install llvm

4.解决办法

1
2
3
4
5
6
7
# 1. 修改makefile的 变量配置,使其使用clang++
CXX = clang++
CC = clang
# 2. 通过llvm 安装新的clang编译器
brew install llvm
# 3. 配置环境变量
export PATH="/usr/local/opt/llvm/bin:$PATH"

mac自带的clang(xcode/commondlinetools) 编译器和基于llvm的编译器存在差异。
mac已经有llvm ,有必要再 brew install llvm 吗?需要通过llvm安装新的clang,并且方便管理维护

6. C++环境验证

6.1 当前环境下使用的 c++的标准库路径?

怎么看当前环境下使用的 c++的标准库路径呢。

1
2
3
4
5
6
7
8
9
# GCC
g++ -print-search-dirs
g++ -print-file-name=libstdc++.a
g++ -print-file-name=libstdc++.so

# Clang
clang++ -print-search-dirs
clang++ -print-file-name=libc++.dylib
clang++ -print-file-name=libc++.a

6.2 vscode环境